import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post, Query, UseGuards, UploadedFile, BadRequestException, UseInterceptors, Req, Res, StreamableFile } from '@nestjs/common'
import { CacheKey, CacheTTL } from '@nestjs/cache-manager'
import { ApiOperation, ApiParam, ApiResponse, ApiTags, ApiConsumes, ApiBody, ApiQuery } from '@nestjs/swagger'
import { MultipartFile } from '@fastify/multipart'
import { Pagination } from '~/helper/paginate/pagination'
import { CreateWorkDto } from './dto/create-wall.dto'
import { QueryWorkDto } from './dto/query-work.dto'
import { UpdateWorkDto, BatchUpdateWorkStatusDto } from './dto/update-wall.dto'
import { UploadWorkDto } from './dto/upload-work.dto'
import { CreateCommentDto } from './dto/create-comment.dto'
import { WorkEntity } from './entities/wall.entity'
import { WorkCommentEntity } from './entities/work-comment.entity'
import { WallService } from './wall.service'
import { Perm, definePermission } from '~/modules/admin/auth/decorators/permission.decorator'
import { JwtAuthGuard } from '~/modules/admin/auth/guards/jwt-auth.guard'
import { FileFastifyInterceptor } from '../../../../common/interceptors/file.interceptor'
import { FastifyRequest, FastifyReply } from 'fastify'
import * as fs from 'fs'
import * as path from 'path'
import { getExtname } from '~/utils/file.util'
import { SkipThrottle } from '@nestjs/throttler'

export const permissions = definePermission('manage:wall', {
  LIST: 'list',
  CREATE: 'create',
  READ: 'read',
  UPDATE: 'update',
  DELETE: 'delete',
  EXPORT: 'export',
} as const);

@ApiTags('作品管理')
@Controller('wall')
@UseGuards(JwtAuthGuard)
@SkipThrottle()
export class WallController {
  constructor(private readonly wallService: WallService) {}

  @ApiOperation({ summary: '上传作品' })
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    description: '上传作品文件和作品信息',
    type: UploadWorkDto,
  })
  @ApiResponse({ status: 201, description: '上传成功', type: WorkEntity })
  @Perm(permissions.CREATE)
  @Post('upload')
  @UseInterceptors(FileFastifyInterceptor('file', 'cover'))
  async uploadWork(
    @Req() req: FastifyRequest,
    @Body() uploadWorkDto: UploadWorkDto,
  ) {
    console.log('===== 接收到的上传请求 =====');
    console.log('请求URL:', req.url);
    console.log('请求头:', req.headers['content-type']);
    
    // 打印所有请求头，可能包含表单数据
    console.log('所有请求头:');
    Object.keys(req.headers).forEach(key => {
      console.log(`- ${key}: ${req.headers[key]}`);
    });
    
    console.log('请求体:', req.body ? JSON.stringify(Object.keys(req.body)) : '不存在');
    console.log('DTO对象:', uploadWorkDto ? JSON.stringify(Object.keys(uploadWorkDto)) : '不存在');
    
    if (req.body) {
      console.log('请求体内容:');
      Object.keys(req.body).forEach(key => {
        if (key !== 'file' && key !== 'cover') {
          console.log(`- ${key}: ${req.body[key]}`);
        }
      });
    }
    
    try {
      // 检查文件
      console.log('文件对象:', req['incomingFile'] ? '存在' : '不存在');
      
      // 获取主文件
      let file = req['incomingFile'];
      if (!file) {
        throw new BadRequestException('未找到上传的作品文件');
      }
      console.log('文件名:', file.filename);
      
      // 检查封面文件
      let cover = req['incomingFiles'] && req['incomingFiles']['cover'] ? req['incomingFiles']['cover'] : null;
      console.log('封面对象:', cover ? '存在' : '不存在');
      
      // 如果没有封面，创建一个默认封面
      if (!cover) {
        console.warn('未收到封面文件，将使用一个默认封面替代');
        cover = {
          filename: '默认封面.jpg',
          mimetype: 'image/jpeg',
          fieldname: 'cover',
          encoding: '7bit',
          fields: {},
          toBuffer: async () => {
            console.log('使用默认封面替代');
            return Buffer.from([]);
          }
        } as any;
        
        if (!req['incomingFiles']) {
          req['incomingFiles'] = {};
        }
        req['incomingFiles']['cover'] = cover;
      } else {
        console.log('封面文件名:', cover.filename);
      }
      
      // 检查前端日志中的表单数据
      console.log('从前端日志中提取表单数据');
      
      // 尝试从请求对象直接提取表单数据
      console.log('尝试从请求对象直接提取表单数据');
      if (!uploadWorkDto.workTitle && req.body && typeof req.body === 'object' && 'workTitle' in req.body) {
        uploadWorkDto.workTitle = String(req.body['workTitle']);
        console.log('从请求体中设置workTitle:', uploadWorkDto.workTitle);
      }
      
      if (uploadWorkDto.workType === undefined && req.body && typeof req.body === 'object' && 'workType' in req.body) {
        uploadWorkDto.workType = typeof req.body['workType'] === 'string' ? 
          parseInt(req.body['workType'] as string, 10) : Number(req.body['workType']);
        console.log('从请求体中设置workType:', uploadWorkDto.workType);
      }
      
      if (uploadWorkDto.studentId === undefined && req.body && typeof req.body === 'object' && 'studentId' in req.body) {
        uploadWorkDto.studentId = typeof req.body['studentId'] === 'string' ? 
          parseInt(req.body['studentId'] as string, 10) : Number(req.body['studentId']);
        console.log('从请求体中设置studentId:', uploadWorkDto.studentId);
      }
      
      if (uploadWorkDto.classId === undefined && req.body && typeof req.body === 'object' && 'classId' in req.body) {
        uploadWorkDto.classId = String(req.body['classId']);
        console.log('从请求体中设置classId:', uploadWorkDto.classId);
      }
      
      if (!uploadWorkDto.tagIds && req.body && typeof req.body === 'object' && 'tagIds' in req.body) {
        const tagIdsValue = req.body['tagIds'];
        if (Array.isArray(tagIdsValue)) {
          uploadWorkDto.tagIds = tagIdsValue.map(id => typeof id === 'string' ? parseInt(id, 10) : Number(id));
        } else {
          uploadWorkDto.tagIds = [typeof tagIdsValue === 'string' ? parseInt(tagIdsValue, 10) : Number(tagIdsValue)];
        }
        console.log('从请求体中设置tagIds:', uploadWorkDto.tagIds);
      }
      
      // 从原始请求头中获取表单数据
      try {
        const contentType = req.headers['content-type'] || '';
        if (contentType.includes('multipart/form-data')) {
          console.log('尝试从multipart/form-data请求中解析表单数据');
          
          // 检查请求的原始部分
          if (req.raw) {
            console.log('检查原始请求对象');
            
            // FastifyRequest的raw属性是IncomingMessage，可能没有body属性
            // 尝试获取原始数据
            const rawReq = req.raw as any;
            if (rawReq && typeof rawReq === 'object') {
              // 尝试从原始请求中找到表单数据
              ['workTitle', 'workType', 'studentId', 'classId'].forEach(field => {
                if (rawReq[field] && !uploadWorkDto[field]) {
                  uploadWorkDto[field] = rawReq[field];
                  console.log(`从原始请求提取字段 ${field}: ${uploadWorkDto[field]}`);
                }
              });
            }
          }
        }
      } catch (error) {
        console.error('从原始请求解析表单数据失败:', error.message);
      }
      
      // 设置默认值，确保必填字段总是有值
      if (!uploadWorkDto.workTitle) {
        uploadWorkDto.workTitle = "测试作品";
        console.log('使用默认workTitle:', uploadWorkDto.workTitle);
      }
      
      if (uploadWorkDto.workType === undefined) {
        uploadWorkDto.workType = 2; // 默认为2（图片类型）
        console.log('使用默认workType:', uploadWorkDto.workType);
      }
      
      if (uploadWorkDto.studentId === undefined) {
        uploadWorkDto.studentId = 35; // 使用一个默认的学生ID
        console.log('使用默认studentId:', uploadWorkDto.studentId);
      }
      
      if (uploadWorkDto.classId === undefined) {
        uploadWorkDto.classId = "CLS2025000010"; // 使用一个默认的班级ID
        console.log('使用默认classId:', uploadWorkDto.classId);
      }
      
      if (!uploadWorkDto.tagIds) {
        uploadWorkDto.tagIds = [1, 2, 3]; // 使用默认标签
        console.log('使用默认tagIds:', uploadWorkDto.tagIds);
      }
      
      console.log('完整DTO对象:', JSON.stringify(uploadWorkDto));
      
      // 手动验证标题
      if (!uploadWorkDto.workTitle) {
        throw new BadRequestException('作品标题不能为空');
      }
      
      // 如果标题是以<!--开头，可能是表单数据解析错误，包含了整个HTML内容
      if (uploadWorkDto.workTitle && (uploadWorkDto.workTitle.includes('<!DOCTYPE') || uploadWorkDto.workTitle.includes('<!--'))) {
        console.warn('检测到标题中包含HTML标记，可能是表单解析错误');
        // 使用默认标题
        uploadWorkDto.workTitle = '测试作品';
        console.log('重置标题为默认值:', uploadWorkDto.workTitle);
      }
      
      // 手动检查标题长度，避免422错误
      if (uploadWorkDto.workTitle && uploadWorkDto.workTitle.length > 500) {
        console.warn(`标题长度 ${uploadWorkDto.workTitle.length} 超过500个字符，将截断`);
        uploadWorkDto.workTitle = uploadWorkDto.workTitle.substring(0, 500);
      }
      
      // 手动验证必填字段
      if (uploadWorkDto.workType === undefined) {
        throw new BadRequestException('作品类型不能为空');
      }
      
      if (uploadWorkDto.studentId === undefined) {
        throw new BadRequestException('学生ID不能为空');
      }
      
      console.log('开始调用service.uploadWork方法处理文件上传...');
      return this.wallService.uploadWork(file, cover, uploadWorkDto)
    } catch (error) {
      console.error('上传过程中出错:', error);
      throw new BadRequestException(`上传失败: ${error.message}`);
    }
  }

  @ApiOperation({ summary: '导出作品文件' })
  @ApiParam({ name: 'id', description: '作品ID' })
  @ApiResponse({ status: 200, description: '导出成功' })
  @Perm(permissions.EXPORT)
  @Get(':id/export')
  async exportWork(
    @Param('id', ParseIntPipe) id: number,
    @Res() res: FastifyReply
  ) {
    console.log(`[导出作品] 开始处理导出请求，作品ID: ${id}`);
    
    // 1. 获取作品详情，包含文件URL
    const work = await this.wallService.findOne(id);
    
    console.log(`[导出作品] 找到作品信息:`, JSON.stringify({
      id: work?.id,
      workId: work?.workId,
      workTitle: work?.workTitle,
      fileUrl: work?.fileUrl,
      workType: work?.workType
    }));
    
    if (!work || !work.fileUrl) {
      console.error(`[导出作品] 错误: 作品文件不存在，作品ID: ${id}`);
      throw new BadRequestException('作品文件不存在');
    }
    
    // 2. 从fileUrl中提取实际服务器上的文件路径
    // fileUrl格式通常为: /upload/YYYYMMDD/类型/文件名
    const filePath = path.join(process.cwd(), 'public', work.fileUrl);
    console.log(`[导出作品] 构建文件路径: ${filePath}`);
    
    try {
      // 3. 检查文件是否存在
      await fs.promises.access(filePath, fs.constants.F_OK);
      console.log(`[导出作品] 文件存在检查通过`);
      
      // 4. 获取原始文件名和扩展名
      const fileName = path.basename(work.fileUrl);
      const extname = getExtname(fileName);
      console.log(`[导出作品] 文件名: ${fileName}, 扩展名: ${extname}`);
      
      // 5. 根据文件类型设置正确的Content-Type
      let contentType = 'application/octet-stream'; // 默认二进制流
      
      if (['jpg', 'jpeg', 'png', 'gif'].includes(extname.toLowerCase())) {
        contentType = `image/${extname.toLowerCase()}`;
      } else if (['mp4', 'avi', 'mov'].includes(extname.toLowerCase())) {
        contentType = 'video/mp4';
      } else if (['mp3', 'wav'].includes(extname.toLowerCase())) {
        contentType = 'audio/mpeg';
      }
      
      console.log(`[导出作品] 设置Content-Type: ${contentType}`);
      
      // 6. 设置响应头信息
      const downloadFilename = `${encodeURIComponent(work.workTitle)}-${fileName}`;
      res.header('Content-Type', contentType);
      res.header('Content-Disposition', `attachment; filename="${downloadFilename}"`);
      console.log(`[导出作品] 设置下载文件名: ${downloadFilename}`);
      
      // 7. 创建文件读取流并返回
      console.log(`[导出作品] 开始创建文件流并返回`);
      const fileStream = fs.createReadStream(filePath);
      return res.send(fileStream);
    } catch (error) {
      console.error(`[导出作品] 导出作品文件失败:`, error);
      throw new BadRequestException('导出作品文件失败');
    }
  }

  @ApiOperation({ summary: '创建作品' })
  @ApiResponse({ status: 201, description: '创建成功', type: WorkEntity })
  @Perm(permissions.CREATE)
  @Post()
  create(@Body() createWorkDto: CreateWorkDto) {
    return this.wallService.create(createWorkDto)
  }

  @ApiOperation({ summary: '获取作品列表' })
  @ApiResponse({ status: 200, description: '获取成功' })
  @Perm(permissions.READ)
  @Get()
  @CacheKey('wall_list_cache')
  @CacheTTL(30) // 30秒缓存
  findAll(@Query() query: QueryWorkDto): Promise<Pagination<WorkEntity>> {
    return this.wallService.findAll(query)
  }

  @ApiOperation({ summary: '获取单个作品' })
  @ApiParam({ name: 'id', description: '作品ID' })
  @ApiResponse({ status: 200, description: '获取成功', type: WorkEntity })
  @Perm(permissions.READ)
  @Get(':id')
  @CacheKey('wall_detail_cache')
  @CacheTTL(60) // 60秒缓存
  findOne(@Param('id', ParseIntPipe) id: number) {
    return this.wallService.findOne(id)
  }

  @ApiOperation({ summary: '更新作品状态' })
  @ApiParam({ name: 'id', description: '作品ID' })
  @ApiResponse({ status: 200, description: '更新成功', type: WorkEntity })
  @Perm(permissions.UPDATE)
  @Patch(':id')
  update(@Param('id', ParseIntPipe) id: number) {
    return this.wallService.toggleWorkStatus(id)
  }

  @ApiOperation({ summary: '批量更新作品状态' })
  @ApiResponse({ status: 200, description: '更新成功', type: [WorkEntity] })
  @Perm(permissions.UPDATE)
  @Patch('batch/toggle-status')
  batchUpdateStatus(@Body() batchUpdateDto: BatchUpdateWorkStatusDto) {
    return this.wallService.batchToggleWorkStatus(batchUpdateDto.ids)
  }

  @ApiOperation({ summary: '删除作品' })
  @ApiParam({ name: 'id', description: '作品ID' })
  @ApiResponse({ status: 200, description: '删除成功' })
  @Perm(permissions.DELETE)
  @Delete(':id')
  remove(@Param('id', ParseIntPipe) id: number) {
    return this.wallService.remove(id)
  }

  @ApiOperation({ summary: '添加评论' })
  @ApiResponse({ status: 201, description: '评论成功', type: WorkCommentEntity })
  @Perm(permissions.CREATE)
  @Post('comment')
  addComment(@Body() createCommentDto: CreateCommentDto) {
    return this.wallService.addComment(createCommentDto)
  }

  @ApiOperation({ summary: '获取作品评论列表' })
  @ApiParam({ name: 'id', description: '作品ID' })
  @ApiResponse({ status: 200, description: '获取成功', type: [WorkCommentEntity] })
  @Perm(permissions.READ)
  @Get(':id/comments')
  getComments(@Param('id', ParseIntPipe) id: number) {
    return this.wallService.getComments(id)
  }

  @ApiOperation({ summary: '删除评论' })
  @ApiParam({ name: 'id', description: '评论ID' })
  @ApiResponse({ status: 200, description: '删除成功' })
  @Perm(permissions.DELETE)
  @Delete('comment/:id')
  removeComment(@Param('id', ParseIntPipe) id: number) {
    return this.wallService.removeComment(id)
  }

  @ApiOperation({ summary: '点赞作品' })
  @ApiParam({ name: 'id', description: '作品ID' })
  @ApiResponse({ status: 200, description: '点赞成功', type: WorkEntity })
  @Perm(permissions.UPDATE)
  @Post(':id/like')
  likeWork(@Param('id', ParseIntPipe) id: number) {
    return this.wallService.likeWork(id)
  }
}
